/*--
 * Ls.cs: Lists the contents of a directory, a la the ls command.
 *--
 * For more information, please visit the Metashell Project site:
 *   http://code.google.com/p/metashell/
 *--
 * (c) 2006 Christopher E. Granade.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; exactly version 2
 * of the License applies to this software.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Metashell.Core;

namespace Metashell.Commands.Basic {

	public class Ls : ICommand {
	
		private Metashell.Core.Core core;
		
		public const string NamespaceURI =
			MetadocNamespaces.FileList;
		
		public void RegisterCore(Metashell.Core.Core core_) {
			core = core_;
		}
		
		public string name {
			get { return "ls"; }
		}
		
		public void Run(
			string parameters,
			Metadoc indoc,
			out Metadoc outdoc
		) {
			
			string curdir;
			
			if (parameters.Length != 0 && Directory.Exists(parameters)) {
				curdir = parameters;
			} else {
				curdir = core.CurrentDirectory;
			}
			
			outdoc.data = new XmlDocument();
			XmlElement root = outdoc.data.CreateElement(
				"fl", "filelist", NamespaceURI);
			outdoc.data.AppendChild(root);
			outdoc.format = MetadocFormats.FileList;
			
			// Build a list of files and a list of directories.
			// Then add each to a dictionary as the key, with the value being
			// an XML element associated with the entry.
			
			string[] files, dirs;
			SortedList<string, XmlElement> list =
				new SortedList<string, XmlElement>();
			
			files = Directory.GetFiles(curdir);
			dirs = Directory.GetDirectories(curdir);
			
			foreach (string f in files) {				
				list.Add(f, MkElement(f, ref outdoc.data));				
			}
			
			foreach (string d in dirs) {
				list.Add(d, MkElement(d, ref outdoc.data));
			}
			
			foreach (KeyValuePair<string, XmlElement> kvp in list) {
				root.AppendChild(kvp.Value);
			}
			
		}
		
		private XmlElement MkElement(
			string file, ref XmlDocument fromdoc)
		{
			
			FileAttributes attrs = File.GetAttributes(file);
				
			XmlElement xe = fromdoc.CreateElement("fl",
				((attrs & FileAttributes.Directory) > 0) ? "dir" : "file",
				NamespaceURI);
			
			xe.SetAttribute("name", NamespaceURI,
				Path.GetFileName(file));
			xe.SetAttribute("createtime", NamespaceURI,
				File.GetCreationTimeUtc(file).ToString());
			xe.SetAttribute("modtime", NamespaceURI,
				File.GetLastWriteTimeUtc(file).ToString());
			xe.SetAttribute("accesstime", NamespaceURI,
				File.GetLastWriteTimeUtc(file).ToString());
			xe.SetAttribute("archive", NamespaceURI,
				AttrString(FileAttributes.Archive, attrs));
			xe.SetAttribute("compressed", NamespaceURI,
				AttrString(FileAttributes.Compressed, attrs));
			xe.SetAttribute("device", NamespaceURI,
				AttrString(FileAttributes.Device, attrs));
			xe.SetAttribute("encrypted", NamespaceURI,
				AttrString(FileAttributes.Encrypted, attrs));
			xe.SetAttribute("hidden", NamespaceURI,
				AttrString(FileAttributes.Hidden, attrs));
			xe.SetAttribute("not-indexed", NamespaceURI,
				AttrString(FileAttributes.NotContentIndexed, attrs));
			xe.SetAttribute("offline", NamespaceURI,
				AttrString(FileAttributes.Offline, attrs));
			xe.SetAttribute("readonly", NamespaceURI,
				AttrString(FileAttributes.ReadOnly, attrs));
			xe.SetAttribute("sparse", NamespaceURI,
				AttrString(FileAttributes.SparseFile, attrs));
			xe.SetAttribute("system", NamespaceURI,
				AttrString(FileAttributes.System, attrs));
			xe.SetAttribute("temp", NamespaceURI,
				AttrString(FileAttributes.Temporary, attrs));
			
			// TODO: If under Unix, then add Mono.Posix stuff here.			
			
			return xe;
			
		}
		
		private string AttrString(
			System.IO.FileAttributes attr, System.IO.FileAttributes attrs) {
		
			return ((attr & attrs) > 0).ToString().ToLower();
		
		}
		
	}

}